{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多因子模型分析\n",
    "\n",
    "本笔记本实现Fama-French三因子模型和五因子模型的分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import statsmodels.api as sm\n",
    "import akshare as ak\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 设置中文显示\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
    "plt.rcParams['axes.unicode_minus'] = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_factor_data():\n",
    "    \"\"\"\n",
    "    获取Fama-French因子数据\n",
    "    \n",
    "    Returns:\n",
    "        pd.DataFrame: 包含因子数据的DataFrame\n",
    "    \"\"\"\n",
    "    # 这里使用akshare获取因子数据\n",
    "    # 实际使用时需要替换为真实数据源\n",
    "    try:\n",
    "        # 示例数据 - 实际应替换为真实因子数据\n",
    "        dates = pd.date_range('2010-01-01', '2023-12-31', freq='M')\n",
    "        data = {\n",
    "            'MKT': np.random.normal(0.01, 0.05, len(dates)),\n",
    "            'SMB': np.random.normal(0.005, 0.03, len(dates)),\n",
    "            'HML': np.random.normal(0.008, 0.02, len(dates)),\n",
    "            'RMW': np.random.normal(0.006, 0.015, len(dates)),\n",
    "            'CMA': np.random.normal(0.004, 0.01, len(dates))\n",
    "        }\n",
    "        return pd.DataFrame(data, index=dates)\n",
    "    except Exception as e:\n",
    "        print(f\"获取因子数据失败: {e}\")\n",
    "        return pd.DataFrame()\n",
    "\n",
    "def get_stock_returns(stock_code):\n",
    "    \"\"\"\n",
    "    获取个股收益率数据\n",
    "    \n",
    "    Args:\n",
    "        stock_code: 股票代码\n",
    "        \n",
    "    Returns:\n",
    "        pd.Series: 月收益率序列\n",
    "    \"\"\"\n",
    "    try:\n",
    "        # 使用akshare获取股票数据\n",
    "        df = ak.stock_zh_a_hist(symbol=stock_code, period=\"monthly\", adjust=\"qfq\")\n",
    "        df['日期'] = pd.to_datetime(df['日期'])\n",
    "        df = df.set_index('日期').sort_index()\n",
    "        return df['收盘'].pct_change().dropna()\n",
    "    except Exception as e:\n",
    "        print(f\"获取股票数据失败: {e}\")\n",
    "        return pd.Series()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 三因子模型分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def three_factor_model(stock_returns, factors):\n",
    "    \"\"\"\n",
    "    三因子模型回归分析\n",
    "    \n",
    "    Args:\n",
    "        stock_returns: 个股收益率\n",
    "        factors: 因子数据\n",
    "        \n",
    "    Returns:\n",
    "        RegressionResults: 回归结果对象\n",
    "    \"\"\"\n",
    "    try:\n",
    "        # 对齐数据\n",
    "        merged = pd.concat([stock_returns, factors[['MKT', 'SMB', 'HML']]], axis=1, join='inner')\n",
    "        merged.columns = ['Return', 'MKT', 'SMB', 'HML']\n",
    "        \n",
    "        # 准备回归数据\n",
    "        X = sm.add_constant(merged[['MKT', 'SMB', 'HML']])\n",
    "        y = merged['Return']\n",
    "        \n",
    "        # 运行回归\n",
    "        model = sm.OLS(y, X).fit()\n",
    "        return model\n",
    "    except Exception as e:\n",
    "        print(f\"三因子模型分析失败: {e}\")\n",
    "        return None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 五因子模型分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def five_factor_model(stock_returns, factors):\n",
    "    \"\"\"\n",
    "    五因子模型回归分析\n",
    "    \n",
    "    Args:\n",
    "        stock_returns: 个股收益率\n",
    "        factors: 因子数据\n",
    "        \n",
    "    Returns:\n",
    "        RegressionResults: 回归结果对象\n",
    "    \"\"\"\n",
    "    try:\n",
    "        # 对齐数据\n",
    "        merged = pd.concat([stock_returns, factors], axis=1, join='inner')\n",
    "        merged.columns = ['Return', 'MKT', 'SMB', 'HML', 'RMW', 'CMA']\n",
    "        \n",
    "        # 准备回归数据\n",
    "        X = sm.add_constant(merged[['MKT', 'SMB', 'HML', 'RMW', 'CMA']])\n",
    "        y = merged['Return']\n",
    "        \n",
    "        # 运行回归\n",
    "        model = sm.OLS(y, X).fit()\n",
    "        return model\n",
    "    except Exception as e:\n",
    "        print(f\"五因子模型分析失败: {e}\")\n",
    "        return None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 主分析流程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取数据\n",
    "factors = get_factor_data()\n",
    "stock_returns = get_stock_returns('600519')  # 贵州茅台\n",
    "\n",
    "# 三因子模型分析\n",
    "model_3f = three_factor_model(stock_returns, factors)\n",
    "if model_3f:\n",
    "    print(\"三因子模型回归结果:\")\n",
    "    print(model_3f.summary())\n",
    "\n",
    "# 五因子模型分析\n",
    "model_5f = five_factor_model(stock_returns, factors)\n",
    "if model_5f:\n",
    "    print(\"\\n五因子模型回归结果:\")\n",
    "    print(model_5f.summary())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 因子贡献度分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_factor_contribution(model):\n",
    "    \"\"\"\n",
    "    绘制因子贡献度\n",
    "    \n",
    "    Args:\n",
    "        model: 回归模型结果\n",
    "    \"\"\"\n",
    "    if not model:\n",
    "        return\n",
    "        \n",
    "    try:\n",
    "        # 获取因子系数\n",
    "        coefs = model.params.drop('const')\n",
    "        \n",
    "        # 绘制柱状图\n",
    "        plt.figure(figsize=(10, 6))\n",
    "        coefs.plot(kind='bar')\n",
    "        plt.title('因子贡献度分析')\n",
    "        plt.ylabel('因子暴露')\n",
    "        plt.axhline(0, color='black', linestyle='--')\n",
    "        plt.show()\n",
    "    except Exception as e:\n",
    "        print(f\"绘制因子贡献度失败: {e}\")\n",
    "\n",
    "# 绘制三因子模型贡献度\n",
    "plot_factor_contribution(model_3f)\n",
    "\n",
    "# 绘制五因子模型贡献度\n",
    "plot_factor_contribution(model_5f)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}